var ScrambledEggs;
(function (ScrambledEggs) {
    var Glyph = (function () {
        function Glyph(LevelCharacter, IsWalkable, DisplayCharacter, DisplayColor, EntryFunction) {
            if (typeof DisplayCharacter === "undefined") { DisplayCharacter = null; }
            if (typeof DisplayColor === "undefined") { DisplayColor = null; }
            if (typeof EntryFunction === "undefined") { EntryFunction = null; }
            this.LevelCharacter = LevelCharacter;
            this.IsWalkable = IsWalkable;
            this.DisplayCharacter = DisplayCharacter;
            this.DisplayColor = DisplayColor;
            this.EntryFunction = EntryFunction;
            if(this.DisplayCharacter == null) {
                this.DisplayCharacter = this.LevelCharacter;
            }
            if(this.DisplayColor == null) {
                this.DisplayColor = "#FFFFFF";
            }
            if(this.EntryFunction == null) {
                this.EntryFunction = $.noop;
            }
        }
        return Glyph;
    })();
    ScrambledEggs.Glyph = Glyph;    
    var Coordinate = (function () {
        function Coordinate(X, Y) {
            this.X = X;
            this.Y = Y;
        }
        Coordinate.prototype.Clone = function () {
            return new Coordinate(this.X, this.Y);
        };
        return Coordinate;
    })();
    ScrambledEggs.Coordinate = Coordinate;    
    var Tile = (function () {
        function Tile(Position, Glyph) {
            this.Position = Position;
            this.Glyph = Glyph;
        }
        return Tile;
    })();
    ScrambledEggs.Tile = Tile;    
    var Adventure = (function () {
        function Adventure(level, glyphs, characterGlyph, Canvas) {
            this.Canvas = Canvas;
            this.GlyphWidth = 15;
            this.GlyphHeight = 15;
            this.MoveSpeed = 300;
            this.MoveStartTime = 0;
            this.MoveEndTime = 0;
            this.TextColor = "rgb(20, 0, 0)";
            var me = this;
            me.Ctx = (Canvas).getContext("2d");
            me.Ctx.font = "14px Courier New";
            me.CharacterGlyph = characterGlyph;
            me._canvasGlyphHeight = Math.floor((Canvas).height / me.GlyphHeight);
            me._canvasGlyphWidth = Math.floor((Canvas).width / me.GlyphWidth);
            glyphs["+"] = new Glyph("+", function () {
                return false;
            });
            glyphs["/"] = new Glyph(" ", function () {
                return false;
            });
            if(glyphs[" "] == null) {
                glyphs[" "] = new Glyph(" ", function () {
                    return true;
                });
            }
            me.GlyphField = {
            };
            for(var char in glyphs) {
                var glyph = glyphs[char];
                if(glyph.LevelCharacter != char && char != "/") {
                    throw "Glyph level character is inconsistent: " + char + "->" + glyph.LevelCharacter;
                }
                me.GlyphField[char] = [];
            }
            me.Playfield = [];
            var rows = level.split("\n");
            var rowCounter = 0;
            var rowWidth = 0;
            for(var y = 0, ylen = rows.length; y < ylen; y++) {
                var row = rows[y].trim();
                if(me._fieldGlyphWidth == null) {
                    me._fieldGlyphWidth = row.length;
                }
                if(row.length != me._fieldGlyphWidth) {
                    throw "row " + (row + 1) + "has " + row.length + " characters instead of " + me._fieldGlyphWidth;
                }
                me.Playfield.push([]);
                var playfieldRow = me.Playfield[rowCounter];
                for(var x = 0, xlen = row.length; x < xlen; x++) {
                    var glyph = glyphs[row[x]];
                    if(glyph == null) {
                        if(characterGlyph.LevelCharacter == row[x]) {
                            glyph = glyphs[" "];
                            me.Position = new Coordinate(x, rowCounter);
                        } else {
                            console.log("Unrecognized glyph in field: '" + row[x] + "' at row " + y + " col " + (x + 1));
                            glyph = new Glyph("/", function () {
                                return false;
                            }, row[x].toUpperCase(), me.TextColor, $.noop);
                        }
                    }
                    var tile = new Tile(new Coordinate(x, rowCounter), glyph);
                    playfieldRow.push(tile);
                    me.GlyphField[glyph.LevelCharacter].push(tile);
                }
                rowCounter++;
            }
            me._fieldGlyphHeight = me.Playfield.length;
        }
        Adventure.prototype.Start = function () {
            var me = this;
            var loop = new ScrambledEggs.DrawLoop(function (state) {
                me.Update(state);
            });
            loop.setDrawables([
                this
            ]);
        };
        Adventure.prototype.Update = function (state) {
            var me = this;
            var time = state.Time();
            if(time >= me.MoveEndTime) {
                var keyState = state.GetKeyState();
                var moved = false;
                if(keyState.KeyArrowUp()) {
                    if(me.Position.Y > 0 && me.Playfield[me.Position.Y - 1][me.Position.X].Glyph.IsWalkable()) {
                        me.OldPosition = me.Position.Clone();
                        me.MoveStartTime = time;
                        me.MoveEndTime = time + me.MoveSpeed;
                        me.Position.Y--;
                        moved = true;
                    }
                } else if(keyState.KeyArrowDown()) {
                    if(me.Position.Y < me._fieldGlyphHeight && me.Playfield[me.Position.Y + 1][me.Position.X].Glyph.IsWalkable()) {
                        me.OldPosition = me.Position.Clone();
                        me.MoveStartTime = time;
                        me.MoveEndTime = time + me.MoveSpeed;
                        me.Position.Y++;
                        moved = true;
                    }
                }
                if(keyState.KeyArrowRight()) {
                    if(me.Position.X < me._fieldGlyphWidth - 1 && me.Playfield[me.Position.Y][me.Position.X + 1].Glyph.IsWalkable()) {
                        if(moved) {
                            me.MoveEndTime = time + me.MoveSpeed * 1.7;
                            me.Position.X++;
                        } else {
                            me.OldPosition = me.Position.Clone();
                            me.MoveStartTime = time;
                            me.MoveEndTime = time + me.MoveSpeed;
                            me.Position.X++;
                            moved = true;
                        }
                    }
                } else if(keyState.KeyArrowLeft()) {
                    if(me.Position.X > 0 && me.Playfield[me.Position.Y][me.Position.X - 1].Glyph.IsWalkable()) {
                        if(moved) {
                            me.MoveEndTime = time + me.MoveSpeed * 1.7;
                            me.Position.X--;
                        } else {
                            me.OldPosition = me.Position.Clone();
                            me.MoveStartTime = time;
                            me.MoveEndTime = time + me.MoveSpeed;
                            me.Position.X--;
                            moved = true;
                        }
                    }
                }
                if(moved) {
                    me.Playfield[me.Position.Y][me.Position.X].Glyph.EntryFunction();
                }
            }
        };
        Adventure.prototype.Draw = function (time) {
            var me = this;
            var canvas = me.Canvas;
            var ctx = me.Ctx;
            ctx.clearRect(0, 0, canvas.height, canvas.width);
            var color = "";
            var characterPosition = new Coordinate(Math.floor(me._canvasGlyphWidth / 2), Math.floor(me._canvasGlyphHeight / 2));
            var drawStart = new Coordinate(0, 0);
            me.SetDrawParameters(me.Position, characterPosition, drawStart);
            var interpolation = (time - me.MoveStartTime) / (me.MoveEndTime - me.MoveStartTime);
            if(interpolation > 0 && interpolation < 1) {
                var interpolationRev = 1 - interpolation;
                var characterPositionOld = new Coordinate(Math.floor(me._canvasGlyphWidth / 2), Math.floor(me._canvasGlyphHeight / 2));
                var drawStartOld = new Coordinate(0, 0);
                me.SetDrawParameters(me.OldPosition, characterPositionOld, drawStartOld);
                drawStart.X = drawStart.X * interpolation + drawStartOld.X * interpolationRev;
                drawStart.Y = drawStart.Y * interpolation + drawStartOld.Y * interpolationRev;
                characterPosition.X = characterPosition.X * interpolation + characterPositionOld.X * interpolationRev;
                characterPosition.Y = characterPosition.Y * interpolation + characterPositionOld.Y * interpolationRev;
            }
            for(var y = Math.floor(drawStart.Y), ylen = Math.min(Math.ceil(drawStart.Y) + 1 + me._canvasGlyphHeight, me._fieldGlyphHeight); y < ylen; y++) {
                var row = me.Playfield[y];
                for(var x = Math.floor(drawStart.X), xlen = Math.min(Math.ceil(drawStart.X) + 1 + me._canvasGlyphWidth, me._fieldGlyphWidth); x < xlen; x++) {
                    var tile = row[x];
                    if(color != tile.Glyph.DisplayColor) {
                        ctx.fillStyle = color = tile.Glyph.DisplayColor;
                    }
                    ctx.fillText(tile.Glyph.DisplayCharacter, (x - drawStart.X) * me.GlyphWidth, (y - drawStart.Y) * me.GlyphHeight + me.GlyphHeight);
                }
            }
            ctx.fillStyle = me.CharacterGlyph.DisplayColor;
            ctx.fillText(me.CharacterGlyph.DisplayCharacter, characterPosition.X * me.GlyphWidth, characterPosition.Y * me.GlyphHeight + me.GlyphHeight);
        };
        Adventure.prototype.SetDrawParameters = function (position, characterPosition, drawStart) {
            var me = this;
            var tmpPerf;
            drawStart.X = position.X - characterPosition.X;
            drawStart.Y = position.Y - characterPosition.Y;
            if(drawStart.X < 0) {
                characterPosition.X += drawStart.X;
                drawStart.X = 0;
            } else if(drawStart.X > (tmpPerf = (me._fieldGlyphWidth - me._canvasGlyphWidth))) {
                if(tmpPerf > 0) {
                    characterPosition.X += drawStart.X - tmpPerf;
                    drawStart.X = tmpPerf;
                } else {
                    characterPosition.X += drawStart.X;
                    drawStart.X = 0;
                }
            }
            if(drawStart.Y < 0) {
                characterPosition.Y += drawStart.Y;
                drawStart.Y = 0;
            } else if(drawStart.Y > (tmpPerf = (me._fieldGlyphHeight - me._canvasGlyphHeight))) {
                if(tmpPerf > 0) {
                    characterPosition.Y += drawStart.Y - tmpPerf;
                    drawStart.Y = tmpPerf;
                } else {
                    characterPosition.Y += drawStart.Y;
                    drawStart.Y = 0;
                }
            }
        };
        return Adventure;
    })();
    ScrambledEggs.Adventure = Adventure;    
})(ScrambledEggs || (ScrambledEggs = {}));
